﻿## Get XML configuration file parameters
param 
(
    [string]$ConfigFile = $(throw '- Need parameter input file (e.g. "c:\install-config.xml")')
)

## check to ensure Microsoft.SharePoint.PowerShell is loaded if not using the SharePoint Management Shell 
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'} 
if ($snapin -eq $null) 
{    
	Write-Host "Loading SharePoint Powershell Snapin"    
	Add-PSSnapin "Microsoft.SharePoint.Powershell" 
}

## get the the node Config in the configuration file
$xmlinput = [xml] (get-content $ConfigFile)
$item = $xmlinput.Config

## Read the Farm parameters
$SolutionsFolder = $item.SolutionsFolder
$WebApplicationURL = $item.WebApplication.WebApplicationURL
$WebApplicationName = $item.WebApplication.WebApplicationName
$Port = $item.WebApplication.Port
$ApplicationPool = $item.WebApplication.ApplicationPool
$ApplicationPoolAccount = $item.WebApplication.ApplicationPoolAccount
$HostHeader = $item.WebApplication.HostHeader
$DatabaseName = $item.Database.DatabaseName
$DatabaseServer = $item.Database.DatabaseServer
$Solutions = $item.Solutions
$Features = $item.Features

## write the Farm parameters to the console application
Write-Host -f White "SolutionsFolder: $SolutionsFolder"
Write-Host -f White "WebApplicationURL: $WebApplicationURL"
Write-Host -f White "WebApplicationName: $WebApplicationName"
Write-Host -f White "ApplicationPool: $ApplicationPool"
Write-Host -f White "ApplicationPoolAccount: $ApplicationPoolAccount"
Write-Host -f White "HostHeader: $HostHeader"
Write-Host -f White "DatabaseName: $DatabaseName"
Write-Host -f White "DatabaseServer: $DatabaseServer"

## this method will delete and retract the solution. You will need to call it
## with the solution id and the webapplication. If it is globally deployed just
## leave the web application empty
function DeleteSolution
{
	param ([string]$solutionID, [string]$webApplication)

	$farm = Get-SPFarm

	$sol = $farm.Solutions[$solutionID]

	if($sol)
	{
		Write-Host -f Yellow "Going to uninstall $solutionID"

		if( $sol.Deployed -eq $TRUE ) 
		{
			if ( $webApplication -eq "" )
			{
				Uninstall-SPSolution -Identity $solutionID -Confirm:0
			}
			else 
			{
				Uninstall-SPSolution -Identity $solutionID -Confirm:0 -Webapplication $webApplication
			}

			while( $sol.JobExists ) 
			{
				Write-Host "waiting for retraction."
				sleep 3
			}
		}

		Write-Host -f Yellow "Going to Remove $solutionID"
		Remove-SPSolution -Identity $solutionID -Force -Confirm:0

		Write-Host -f Green $solutionID is deleted from this Farm
	}
	else
	{
		Write-Host -f Yellow "Solution $solutionID not found"
	}
}

## This method installs and deploys a solution based on its solution id, path and web application.
## If the solution should be deployed globally just leave the web application empty
function DeploySolution
{
	param ([string]$solutionID, [string]$solutionPath, [string]$webApplication)

	$filename = $solutionPath + "\" + $solutionID

	Write-Host -f White "Deploy solution $solutionID from $filename to webapplication $webApplication"

	Add-SPSolution $filename

	Write-Host -f Green "Solution $solutionID added"

	Write-Host -f Yellow "Installing $solutionID into web application"

	if ( $webApplication -eq "" )
	{
		Install-SPSolution –Identity $solutionID -GACDeployment -Force
	}
	else
	{
		Install-SPSolution –Identity $solutionID –WebApplication $webApplication -GACDeployment -Force
	}

	$farm = Get-SPFarm

	$sol = $farm.Solutions[$solutionID]

	if($sol)
	{
		Write-Host -f Yellow "Going to install $solutionID"

		while( $sol.Deployed -eq $FALSE )
		{
			Write-Host "waiting for installation."
			sleep 3
		}

		Write-Host -f Green "Solution $solutionID is installed"
	}
	else
	{
		Write-Host -f Red "Installing $solutionID has failed. Solution is not found."
	}
}

function ActivateFeature
{
    param ([string]$featureID, [string]$url)
    
    Write-Host -f Yellow "Activating feature $featureID on url $url"
    
    $feature = Get-SPFeature -Identity $featureID
    if ($feature -ne $Null)
    {
        try
        {
            if ($feature.Scope -eq "Site")
            {
                $feature = Get-SPFeature -Identity $featureID -Site $url
            }
            elseif ($feature.Scope -eq "Web")
            {
                $feature = Get-SPFeature -Identity $featureID -Web $url
            }
            elseif ($feature.Scope -eq "WebApplication")
            {
                $feature = Get-SPFeature -Identity $featureID -WebApplication $url
            }
            elseif ($feature.Scope -eq "Farm")
            {
                $feature = Get-SPFeature -Identity $featureID -Farm
            }
            else
            {
                $feature = $Null
            }
        }
        catch
        {
            $feature = $Null
        }
        
        if ($feature -eq $Null)
        {
            if ($url -eq $Null)
            {
                Enable-SPFeature -Identity $featureID
            }
            else
            {
                Enable-SPFeature -Identity $featureID -Url $url
            }
            
            Write-Host -f Green "Feature $featureID is activated on url $url"
        }
        else
        {
            Write-Host -f Green "Feature $featureID is already activated on url $url"
        }
    }
    else
    {
        Write-Host -f Red "Activating feature $featureID has failed. Feature is not found."
    } 
}

function DeactivateFeature
{
    param ([string]$featureID, [string]$url)
    
    Write-Host -f Yellow "Deactivating feature $featureID on url $url"
    
    $feature = Get-SPFeature -Identity $featureID
    if ($feature -ne $Null)
    {
        try
        {
            if ($feature.Scope -eq "Site")
            {
                $feature = Get-SPFeature -Identity $featureID -Site $url
            }
            elseif ($feature.Scope -eq "Web")
            {
                $feature = Get-SPFeature -Identity $featureID -Web $url
            }
            elseif ($feature.Scope -eq "WebApplication")
            {
                $feature = Get-SPFeature -Identity $featureID -WebApplication $url
            }
            elseif ($feature.Scope -eq "Farm")
            {
                $feature = Get-SPFeature -Identity $featureID -Farm
            }
            else
            {
                $feature = $Null
            }
        }
        catch
        {
            $feature = $Null
        }
            
        if ($feature -ne $Null)
        {    
            if ($url -eq $Null)
            {
                Disable-SPFeature -Identity $featureID -Force -Confirm:$false
            }
            else
            {
                Disable-SPFeature -Identity $featureID -Url $url -Force -Confirm:$false
            }
            
            Write-Host -f Green "Feature $featureID is deactivated on url $url"
        }
        else
        {
            Write-Host -f Green "Feature $featureID was already deactivated on url $url"
        }
    }
    else
    {
        Write-Host -f Red "Deactivating feature $featureID has failed. Feature is not found."
    }
}

## get the web application and if not exist add it based on the data from the config.xml file
$webApp = Get-SPWebApplication $WebApplicationURL -ea SilentlyContinue 
$doCreate = $item.WebApplication.GetAttribute("Create")
if ($webApp -eq $Null -and $doCreate -eq $TRUE)
{
	Write-Host -f Yellow "No web application found. Web application is created"
	New-SPWebApplication -Name $WebApplicationName -ApplicationPool $ApplicationPool -ApplicationPoolAccount $ApplicationPoolAccount -Port $Port -URL $WebApplicationURL -HostHeader $HostHeader -DatabaseName $DatabaseName -DatabaseServer $DatabaseServer

	$webApp = Get-SPWebApplication  $WebApplicationURL -ea SilentlyContinue
}

## start retract, delete, install and deploy all solutions found in the config xml file. When the
## Scoped atrribute is set to true, the solution is retracted and deployed globally
if ($webApp -ne $Null)
{
    Write-Host -f Green "Web application is created/present"

	foreach($solution in $Solutions.ChildNodes)
	{
		$scoped = $solution.GetAttribute("Scoped")
		$solutionName = $solution.InnerText

		if ($scoped -eq $TRUE)
		{
			Write-Host -f White "Solution $solutionName is scoped"
			DeleteSolution -solutionID $solutionName -webApplication $WebApplicationURL
		}
		else
		{
			Write-Host -f White "Solution $solutionName is not scoped"
			DeleteSolution -solutionID $solutionName -webApplication ""
		}
	}

	foreach($solution in $Solutions.ChildNodes)
	{
		$scoped = $solution.GetAttribute("Scoped")
		$solutionName = $solution.InnerText

		if ($scoped -eq $TRUE)
		{
			Write-Host -f White "Solution $solutionName is scoped"
			DeploySolution -solutionID $solutionName -solutionPath $SolutionsFolder -webApplication $WebApplicationURL
		}
		else
		{
			Write-Host -f White "Solution $solutionName is not scoped"
			DeploySolution -solutionID $solutionName -solutionPath $SolutionsFolder -webApplication ""
		}
	}
    
	if ($Features -ne $Null)
	{
		foreach($feature in $Features.ChildNodes)
		{
			$featureUrl = $feature.GetAttribute("Url")
			DeactivateFeature -featureID $feature.InnerText -url $featureUrl
		}
    
		foreach($feature in $Features.ChildNodes)
		{
			$featureUrl = $feature.GetAttribute("Url")
			ActivateFeature -featureID $feature.InnerText -url $featureUrl
		}
	}
}